home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcr
/
pcr4_4.lha
/
DIST
/
threads
/
ThreadsInit.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-16
|
20KB
|
821 lines
/* begincopyright
Copyright (c) 1988 Xerox Corporation. All rights reserved.
Use and copying of this software and preparation of derivative works based
upon this software are permitted. Any distribution of this software or
derivative works must comply with all applicable United States export
control laws. This software is made available AS IS, and Xerox Corporation
makes no warranty about the software, its performance or its conformity to
any specification. Any person obtaining a copy of this software is requested
to send their name and post office or electronic mail address to:
PCR Coordinator
Xerox PARC
3333 Coyote Hill Rd.
Palo Alto, CA 94304
endcopyright */
/*
* ThreadsInit.c
*
* Demers, February 15, 1991 4:02:11 pm PST
* Weiser, October 1989
* Boehm, October 2, 1991 12:17:02 pm PDT
*
* Xerox Runtime threads package initialization.
*/
#include "xr/BasicTypes.h"
#include "xr/Errno.h"
#include "xr/Threads.h"
#include "xr/ThreadsBackdoor.h"
#include "xr/ThreadsPrivate.h"
#include "xr/ThreadsSharedMem.h"
#include "xr/ThreadsMsgPrivate.h"
#include "xr/ThreadsStatsPrivate.h"
#include "xr/ThreadsTermination.h"
#include "xr/ThreadsSignalsPrivate.h"
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <string.h>
#include <sgtty.h>
#include <sys/resource.h>
#define MAX_HEAP_BYTES (128*1024*1024)
#define XR_WARMSTACKSPACE (XR_MIN_THREAD_STACK_BYTES/4)
#define XR_OFLOHANDLERSTACKSPACE (XR_MIN_THREAD_STACK_BYTES/4)
/*
* Utility for calling initialization procs that must succeed ...
*/
#define TRY(callresult, dopanic) XR_FailWithMsg((callresult), (dopanic))
static void
XR_FailWithMsg(msg, pflag)
char *msg;
bool pflag;
{
if( msg ) {
if( pflag ) XR_Panic(msg);
XR_ConsoleMsg("%s\n", msg);
_exit(1);
}
}
/*
* Well-known file descriptors
*/
int XR_stdInFD = 0;
int XR_stdOutFD = 1;
int XR_socket0FD = -1;
int XR_socket1FD = -1;
int XR_freeFD = -1;
static void
XR_MoveDescriptor(from, to)
int from;
int to;
{
if( from == to ) return;
if( (dup2(from, to) < 0) || (close(from) < 0) )
XR_Panic("MoveDescriptor 0");
}
int
XR_InstallDescriptor(d)
int d;
{
int ans;
ans = XR_freeFD;
XR_MoveDescriptor( d, ans );
XR_freeFD -= 1;
return ans;
}
int
XR_SetUnixDescriptorBlocking(fd, blocking)
int fd;
bool blocking;
{
int cFlags;
if( fd < 0 ) return (-EINVAL);
if( (cFlags = fcntl(fd, F_GETFL, NIL)) < 0 ) return (-EIO);
if( blocking )
cFlags &= (~FNDELAY);
else
cFlags |= FNDELAY;
if( fcntl(fd, F_SETFL, cFlags) < 0 ) return (-EIO);
return 0;
}
#define XR_FDTABLEMAX 256
static int
XR_SetDTableSizeMax()
{
struct rlimit rl;
int dt_max;
if( getrlimit(RLIMIT_NOFILE, &rl) == 0) {
dt_max = rl.rlim_max;
if( dt_max > XR_FDTABLEMAX )
dt_max = XR_FDTABLEMAX;
rl.rlim_cur = dt_max;
(void)setrlimit(RLIMIT_NOFILE, &rl);
}
return getdtablesize();
}
static void
XR_CleanUpDescriptors()
{
(void)XR_SetUnixDescriptorBlocking(XR_stdInFD, TRUE);
(void)XR_SetUnixDescriptorBlocking(XR_stdOutFD, TRUE);
}
static void (*XR_cleanUpDescriptors)() = XR_CleanUpDescriptors;
static void
XR_InitDescriptors()
{
int i;
int nFD, segFD;
int sv[2];
int ans;
if(XR_SetDTableSizeMax() < 0)
XR_Panic("InitDescriptors 1");
XR_freeFD = getdtablesize() - 1;
XR_stdInFD = XR_InstallDescriptor(XR_stdInFD);
(void)XR_SetUnixDescriptorBlocking(XR_stdInFD, FALSE);
XR_stdOutFD = XR_InstallDescriptor(XR_stdOutFD);
(void)XR_SetUnixDescriptorBlocking(XR_stdOutFD, FALSE);
ans = socketpair(
/* af */ AF_UNIX,
/* type */ SOCK_DGRAM,
/* protocol */ 0,
/* sv */ &sv[0]
);
if( ans < 0 ) XR_Panic("InitDescriptors 2");
if( sv[0] > sv[1] ) { int temp = sv[0]; sv[1] = sv[0]; sv[1] = temp; }
XR_socket1FD = XR_InstallDescriptor(sv[1]);
XR_socket0FD = XR_InstallDescriptor(sv[0]);
(void)XR_RegisterTerminationCleanupProc(&XR_cleanUpDescriptors, NIL);
}
/*
* Data structure initialization
*/
void
XR_InitThread (t)
XR_Thread t;
{
t->t_errno = 0;
t->t_errnoLock = 0;
t->t_vpeToReschedOnMonitorExit = NIL;
t->t_mlNeeded = NIL;
t->t_index = t - &(XR_sysArea->sa_threadPool[0]);
t->t_timeoutIndex = 0;
t->t_gen = 1;
t->t_sStat = XR_SSTAT_NONE;
t->t_pri = XR_PRI_IDLE;
t->t_when = XR_END_OF_TIME;
t->t_next = NIL;
t->t_tq = NIL;
t->t_schedCtlInfo = 0;
t->t_disabled = 0;
t->t_wNext = NIL;
t->t_wq = NIL;
XR_InitializeCondition(&(t->t_timerCV), XR_WAIT_FOREVER);
XR_EnableAborts( &(t->t_timerCV) );
t->t_swStat = XR_SWSTAT_NONE;
XR_InitHandlerData(&(t->t_handlerData), t);
XR_InitSeg( &(t->t_stack.stack_seg), NIL ); /* updated later */
t->t_stack.stack_handlerInitial = NIL;
t->t_stack.stack_clientInitial = NIL;
t->t_stack.stack_warmLimit = NIL;
t->t_abortable = FALSE;
t->t_abortRequest = FALSE;
t->t_jumpSP = NIL;
t->t_jumpProc = NIL;
t->t_jumpArg = NIL;
XR_InitializeMonitor(&(t->t_ml));
t->t_startProc = NIL;
t->t_result = NIL;
t->t_jStat = XR_JSTAT_NONE;
XR_InitializeCondition(&(t->t_jCVc), XR_WAIT_FOREVER);
XR_InitializeCondition(&(t->t_jCVp), XR_WAIT_FOREVER);
t->t_dbMsg = XR_DB_MSG_NONE;
t->t_dbFreeze = FALSE;
t->t_dbFrozen = FALSE;
t->t_dynEnv = NIL;
(void)bzero( t->t_perThreadData, (sizeof t->t_perThreadData) );
}
void
XR_InitHandlerData (handler, next)
XR_HandlerData handler;
XR_Thread next;
{
handler->hd_proc = NIL;
handler->hd_clientData = NIL;
handler->hd_which = 0;
handler->hd_arg = 0;
handler->hd_result = 0;
}
void
XR_InitIOPOrder (iopo)
XR_IOPOrder iopo;
{
iopo->iopo_next = NIL;
iopo->iopo_done = FALSE;
XR_InitializeCondition( &(iopo->iopo_cv), XR_WAIT_FOREVER );
iopo->iopo_proc = NIL;
iopo->iopo_cancel = NIL;
}
void
XR_InitVPOrder (vpo)
XR_VPOrder vpo;
{
vpo->vpo_proc = NIL;
vpo->vpo_stop = FALSE;
}
void
XR_InitVPE (vpe)
XR_VPE vpe;
{
vpe->vpe_index = vpe - &(XR_sysArea->sa_vpe[0]);
vpe->vpe_pid = 0;
vpe->vpe_pri = XR_PRI_IDLE;
vpe->vpe_doSwitch = FALSE;
vpe->vpe_ticksSinceBoot = 0;
vpe->vpe_orderNum = 0;
vpe->vpe_dbStat = XR_DBSTAT_RUN;
vpe->vpe_rusage = NIL;
}
void
XR_InitIOPE (iope)
XR_IOPE iope;
{
int i;
iope->iope_index = iope - &(XR_sysArea->sa_iope[0]);
iope->iope_pid = 0;
iope->iope_kind = 0; /* to be set later! */
iope->iope_flags = 0;
iope->iope_workerProc = NIL;
XR_InitVPOrder( &(iope->iope_vpOrderBuf) );
XR_InitializeMonitor( &(iope->iope_orderLock) );
XR_InitializeCondition( &(iope->iope_orderAccepted), XR_WAIT_FOREVER );
iope->iope_order = NIL;
for( i = 0; i < XR_MAX_IOPE_CLIENT_DATA; i++ ) {
iope->iope_clientData[i] = 0;
}
}
XR_MesaProc
XR_MakeMesaProc (proc, x)
XR_UntypedProc proc;
XR_Pointer x;
{
XR_MesaProc mp;
if( XR_currThread != NIL ) {
mp = (XR_MesaProc)
(XR_malloc( sizeof(struct XR_MesaProcRep) ));
} else {
mp = (XR_MesaProc)
(XR_AllocSharedSysMem( sizeof(struct XR_MesaProcRep) ));
}
mp->mp_proc = proc;
mp->mp_x = x;
return( mp );
}
static void
XR_CreateThreadsStacksArea()
{
unsigned totalBytes = 0;
unsigned totalThreads = 0;
int i;
for( i = 0; i < XR_maxThreadStackGroups; i++ ) {
unsigned nThreads, nBytes;
nBytes = XR_RoundToPage(
XR_threadStackGroups[i].tsg_stackBytes, XR_ROUND_UP );
XR_threadStackGroups[i].tsg_stackBytes = nBytes;
nThreads = XR_threadStackGroups[i].tsg_numThreads;
totalThreads += nThreads;
totalBytes += nThreads * nBytes;
}
TRY(XR_InitSharedStackMem(totalThreads, totalBytes), TRUE);
}
static void
XR_AssignThreadStackForGroup (t, group)
XR_Thread t;
int group;
{
struct XR_SegRep tSeg;
unsigned bytes;
XR_Pointer stack_address;
bytes = XR_threadStackGroups[group].tsg_stackBytes;
if( bytes != XR_RoundToPage(bytes, XR_ROUND_UP) )
XR_Panic("AssignThreadStackForGroup 0: stacksize not page-multiple");
stack_address = XR_AllocSharedStackMem(t->t_index, bytes);
if( stack_address == NIL )
XR_Panic("AssignThreadStackForGroup 1: out of memory");
XR_InitSeg2( &(t->t_stack.stack_seg), stack_address, bytes );
t->t_stack.stack_handlerInitial =
(stack_address + bytes);
t->t_stack.stack_clientInitial =
(stack_address + bytes - XR_OFLOHANDLERSTACKSPACE);
t->t_stack.stack_warmLimit = (stack_address + XR_WARMSTACKSPACE);
}
/*
* Idle procs.
* These don't start until all VPs have been installed.
*/
static XR_Pointer
XR_Idle (mp)
XR_MesaProc mp;
{
XR_SetPriority(XR_PRI_IDLE);
XR_DisableSignals();
for(;;) {
if( !(XR_vpe->vpe_doSwitch) ) XR_WaitForSignal();
XR_EnableSignals();
XR_Yield();
XR_DisableSignals();
}
#ifdef UNDEFINED
for(;;) {
if( XR_vpe->vpe_doSwitch ) {
XR_EnableSignals();
XR_Yield();
XR_DisableSignals();
} else {
XR_WaitForSignal();
}
}
#endif
}
/*
* A high priority thread that will "bounce" attempts to schedule it.
* This is used if we want to ensure that the currently running thread
* will make progress, even if the UNIX scheduler suspends us once we return
* from ReschedSigHandler. By making this thread runnable instead,
* another vp can pick up the interesting one. If we don't get suspended,
* then we immediately switch back to an interesting thread.
* We try to ensure that scheduling this thread will invoke the
* sigcleanup system call, thus giving UNIX a chance to suspend us
* when we expect it.
*/
XR_Thread XR_trampolineThread = NIL;
struct XR_CVRep XR_trampoline_cv = {0};
bool XR_trampolineOnWQ= FALSE; /* Ready to have state set to WAIT_CV */
int XR_trampolineCount = 0; /* How often did I bounce of the trampoline? */
static XR_Pointer
XR_Trampoline (mp)
XR_MesaProc mp;
{
/* XR_SetPriority doesn't let us do this */
XR_currThread -> t_pri = XR_PRI_SYS_EXCLUSIVE;
XR_trampolineThread = XR_currThread;
XR_InitializeCondition(&XR_trampoline_cv, XR_WAIT_FOREVER);
for (;;) {
while (XR_trampolineOnWQ) {
/* Signal handler hasn't seen me yet. Shouldn't happen. */
kill(XR_vpe -> vpe_pid, XR_SIG_RESCHED);
}
XR_AcquireGSL(&(XR_trampoline_cv.cv_gsl));
XR_trampolineCount++;
XR_DisableSignals();
kill(XR_vpe -> vpe_pid, XR_SIG_RESCHED);
/* Make myself ready for signal handler to make me not runnable */
XR_trampolineOnWQ = TRUE;
XR_AddTlWQ(&(XR_trampoline_cv.cv_wq), XR_currThread);
XR_EnableSignals();
/* The pending Resched signal is delivered here */
}
}
static struct XR_MesaProcRep XR_idleMesaProcRep = { XR_Idle, 0 };
static XR_Pointer
XR_Idle0(mp)
XR_MesaProc mp;
{
extern unsigned XR_StartMainXR();
struct XR_CTRep child1;
struct XR_CTRep child2;
XR_SetPriority(XR_PRI_USER_NORMAL);
if (XR_sysArea->sa_numVP > 1) {
XR_Fork( &(child1), XR_MakeMesaProc(XR_Trampoline, 0) );
}
XR_Fork( &(child2), XR_MakeMesaProc(XR_StartMainXR, 0) );
return (*(XR_idleMesaProcRep.mp_proc))(&XR_idleMesaProcRep);
}
static struct XR_MesaProcRep XR_idle0MesaProcRep = { XR_Idle0, 0 };
void
XR_InitIdleThread(i)
int i;
{
XR_Thread t;
XR_MesaProc mp;
t = XR_RemHdTQ(&(XR_sysArea->sa_freeTQ[0]));
if( t == NIL ) XR_Panic("InitIdleThread");
t->t_pri = XR_PRI_IDLE;
t->t_swStat = XR_SWSTAT_THREAD;
t->t_jumpProc = XR_ForkJumpProc;
mp = ((i == 0) ? &XR_idle0MesaProcRep : &XR_idleMesaProcRep);
t->t_jumpArg = ((unsigned)(mp));
t->t_jumpSP = t->t_stack.stack_clientInitial;
t->t_sStat = XR_SSTAT_READY;
XR_AddTlTQ( &(XR_sysArea->sa_readyTQ[XR_PRI_IDLE]), t );
}
static void
XR_SetupSharedDataSeg()
{
struct XR_SegRep seg;
XR_GetSharedDataSeg( &(seg) );
if( seg.seg_bytes > 0 ) {
TRY(XR_ShareMemInitial(seg.seg_addr), TRUE);
}
}
static struct XR_SARep XR_sysAreaRep;
XR_SA XR_sysArea = NIL;
void
XR_InitSA ()
/*
Allocate, map and initialize system area.
Called by first processor, so XR_sysArea is shared by all.
*/
{
int i, j;
XR_Thread t;
XR_TQ thread_free_queue;
unsigned heap_bytes;
XR_sysArea = &XR_sysAreaRep;
XR_GetSharedDataSeg( &(XR_sysArea->sa_sharedDataSeg) );
XR_InitPSL(&(XR_sysArea->sa_metaLock));
# if XR_DEBUG_METALOCK
XR_sysArea->sa_metaLockerPID = (XR_Pointer)(0);
XR_sysArea->sa_metaLockerName = (XR_Pointer)(NIL);
XR_sysArea->sa_metaLockerThread = (XR_Pointer)(NIL);
# endif /* XR_DEBUG_METALOCK */
XR_InitializeCondition(&(XR_sysArea->sa_threadAvail), XR_MsecToTicks(1000));
XR_InitTQ(&(XR_sysArea->sa_preFreeTQ));
for( i = 0; i < XR_maxThreadStackGroups; i++ ) {
XR_InitTQ(&(XR_sysArea->sa_freeTQ[i]));
}
for( i = 0; i <= XR_PRI_LAST; i++ ) {
XR_InitTQ(&(XR_sysArea->sa_readyTQ[i]));
}
XR_InitializeMonitor(&(XR_sysArea->sa_mlSchedCtl));
XR_sysArea->sa_schedCtlMaster = NIL;
XR_InitializeCondition( &(XR_sysArea->sa_cvSchedCtl), XR_WAIT_FOREVER );
XR_SetBootTime();
XR_sysArea->sa_doTimeouts = FALSE;
XR_sysArea->sa_nTimeouts = 0;
XR_sysArea->sa_ttinRecvd = 0;
XR_sysArea->sa_dbpid = 0; /* updated later */
XR_sysArea->sa_dbData = NIL;
XR_sysArea->sa_dbStat = XR_DBSTAT_RUN;
XR_sysArea->sa_examinee = NIL;
XR_sysArea->sa_numVP = 0; /* updated later */
XR_sysArea->sa_numIOP = 0; /* updated later */
XR_InitializeMonitor(&(XR_sysArea->sa_mlIOP));
XR_sysArea->sa_vpOrderNum = 0;
XR_sysArea->sa_vpOrder = NIL;
XR_InitSG( &(XR_sysArea->sa_vpOrderSem), (1+XR_VP_ORDER_SEM_LAST) );
XR_VSem( &(XR_sysArea->sa_vpOrderSem), XR_VP_ORDER_SEM_LOCK, 1);
XR_sysArea->sa_vpOrderMaster = NIL;
XR_sysArea->sa_heapNum = 0;
/* XR_sysArea->sa_heapSeg initialized below, after XR_AssignThreadStack */
# if XR_STATS
XR_sysArea->sa_stats =
(int *)(XR_AllocSharedSysMem((1+XR_STATS_LAST)*(sizeof(int))));
for( i = 0; i <= XR_STATS_LAST; i++ ) {
XR_sysArea->sa_stats[i] = 0;
}
# else
XR_sysArea->sa_stats = NIL;
# endif
XR_InitializeMonitor( &(XR_sysArea->sa_mlRUsage) );
XR_InitPSL(&(XR_sysArea->sa_terminating));
XR_sysArea->sa_terminationStatus = 0; /* irrelevant */
XR_sysArea->sa_panicMsg = NIL;
for( i = 0; i <= XR_maxThreads; i++ ) {
XR_sysArea->sa_timeouts[i] = NIL;
}
for( i = 0; i < XR_maxVPs; i++ )
XR_InitVPE( &(XR_sysArea->sa_vpe[i]) );
for( i = 0; i < XR_maxIOPs; i++ )
XR_InitIOPE( &(XR_sysArea->sa_iope[i]) );
{ XR_Pointer heapAddr = XR_InitSharedHeapMem( MAX_HEAP_BYTES );
if( heapAddr == NIL ) { XR_Panic("InitSA: can't initialize heap"); }
XR_InitSeg2( &(XR_sysArea->sa_heapSeg), heapAddr, 0 );
}
XR_sysArea->sa_heapLimit = XR_ComputeAddress(
XR_sysArea->sa_heapSeg.seg_addr,
MAX_HEAP_BYTES, XR_ROUND_DOWN );
XR_CreateThreadsStacksArea();
t = &(XR_sysArea->sa_threadPool[0]);
for( i = 0; i < XR_maxThreadStackGroups; i++ ) {
thread_free_queue = &(XR_sysArea->sa_freeTQ[i]);
for( j = 0; j < XR_threadStackGroups[i].tsg_numThreads; j++ ) {
XR_InitThread( t );
XR_AssignThreadStackForGroup(t, i);
t->t_fq = thread_free_queue;
if( (i == 0) && (j < XR_maxVPs) ) {
/* put (maxVPs) threads on idle free queue to get started */
XR_AddTlTQ( thread_free_queue, t );
} else {
XR_AddTlTQ( &(XR_sysArea->sa_preFreeTQ), t );
}
t++;
}
}
for( i = 0; i < XR_MAX_SA_CLIENT_DATA; i++ )
XR_sysArea->sa_clientData[i] = NIL;
for( i = 0; i < XR_maxVPs; i++ )
XR_InitIdleThread(i);
}
/*
* wait for installation
*/
static void
XR_AwaitIOPInstallation(i)
int i;
{
XR_IOPE iope = &(XR_sysArea->sa_iope[i]);
while( iope->iope_pid == 0 ) XR_SpinStep(100000);
}
static void
XR_AwaitVPInstallation(i)
int i;
{
XR_VPE vpe = &(XR_sysArea->sa_vpe[i]);
while( vpe->vpe_pid == 0 ) XR_SpinStep(100000);
}
/*
* Configuration for IOProcessors
*/
typedef struct XR_IOPTableEntryRep {
int (*iopte_config)(/* int nAvail, int default */);
void (*iopte_setup)(/* int base, int cnt */);
void (*iopte_run)();
int iopte_numIOP; /* default value, if necessary */
} * XR_IOPTableEntry;
extern int XR_ConfigSlaveIOP();
extern void XR_SetupSlaveIOP();
extern void XR_RunSlaveIOP();
extern int XR_ConfigUIOIOP();
extern void XR_SetupUIOIOP();
extern void XR_RunUIOIOP();
static struct XR_IOPTableEntryRep XR_iopt[] = {
{
XR_ConfigSlaveIOP,
XR_SetupSlaveIOP,
XR_RunSlaveIOP,
0
},
{
XR_ConfigUIOIOP,
XR_SetupUIOIOP,
XR_RunUIOIOP,
0
}
};
void
XR_InitIOPs(maxIOPs)
int maxIOPs;
{
int iopNum, numIOP, nextNumIOP, cnt, i, child;
XR_IOPTableEntry iopte, ioptLim;
numIOP = 0;
ioptLim = ((XR_IOPTableEntry)(((unsigned)(XR_iopt)) + (sizeof XR_iopt)));
for( iopte = XR_iopt; iopte < ioptLim; iopte++ ) {
if( iopte->iopte_config != NIL ) {
cnt = (*iopte->iopte_config)
( maxIOPs-numIOP, iopte->iopte_numIOP );
} else {
cnt = iopte->iopte_numIOP;
}
if( cnt == 0 ) continue;
nextNumIOP = numIOP + cnt;
if( nextNumIOP > maxIOPs ) XR_Panic("InitIOPs 1");
iopte->iopte_numIOP = cnt;
if( iopte->iopte_setup != NIL ) {
(*(iopte->iopte_setup))(numIOP, cnt);
}
numIOP = nextNumIOP;
}
iopNum = 0;
for( iopte = XR_iopt; iopte < ioptLim; iopte++ ) {
for( i = 0; i < iopte->iopte_numIOP; i++ ) {
int child = fork();
if( child < 0 ) {
XR_Panic("InitIOPs 0");
}
if( child == 0 ) {
int pid = getpid();
XR_iope = &(XR_sysArea->sa_iope[iopNum]);
XR_InstallSigHandlers();
XR_iope->iope_pid = pid;
XR_iope->iope_kind = (unsigned)(iopte->iopte_run);
(*(iopte->iopte_run))();
/*NOTREACHED*/
XR_Panic("InitIOPs 2");
}
iopNum++;
}
}
for( i = 0; i < numIOP; i++ ) {
XR_AwaitIOPInstallation(i);
XR_sysArea->sa_numIOP += 1;
}
}
static void
XR_StartVP(i, n)
int i; /* vp index */
int n; /* number of vps */
{
XR_VPE vpe = &(XR_sysArea->sa_vpe[i]);
int j;
XR_vpe = vpe;
XR_InstallSigHandlers();
XR_sysArea->sa_numVP += 1;
vpe->vpe_pid = getpid();
for( j = 0; j < n; j++ ) XR_AwaitVPInstallation(j);
XR_LockMeta("StartVP");
XR_DispatchNewThread(NIL, XR_SWSTAT_THREAD);
/*NOTREACHED*/
}
void
XR_InitAndRunVPs (numVP)
int numVP;
{
int i;
for( i = (numVP-1); i > 0; i-- ) {
int child = fork();
if( child < 0 ) XR_Panic("InitAndRunVPs: can't fork");
if( child == 0 ) {
XR_StartVP(i, numVP);
/*NOTREACHED*/
} else {
XR_AwaitVPInstallation(i);
}
}
XR_StartVP(0, numVP);
/*NOTREACHED*/
}
void
XR_InitAndRunInner()
{
extern void XR_SetupCommandLoop();
extern void XR_SetupGC();
extern void XR_SetupDynamicLoader();
extern void XR_SetupPackage();
TRY(XR_InitSharedMem(), FALSE);
XR_SetupSharedDataSeg();
TRY(XR_InitSharedSysMem(XR_maxSysMem), TRUE);
XR_InitDescriptors();
XR_InitSA();
XR_SetupCommandLoop();
XR_SetupGC();
XR_SetupDynamicLoader();
XR_SetupPackage();
XR_InitIOPs(XR_maxIOPs);
XR_InitAndRunVPs(XR_maxVPs);
/*NOTREACHED*/
}